Transaction & Locking or Currency Control & Recovery

Transaction
트랜잭션: DBMS에서 데이터를 다루는 논리적인 작업의 단위
DB에서 데이터를 다룰 때 장애가 일어난 경우 데이터를 복구하는 작업의 단위이다.

트랜잭션은 전체가 수행되거나 또는 전혀 수행되지 않아야 한다.(All or Nothing)

DBMS에서 데이터를 다루는 논리적인 작업의 단위
COMMIT 은 트랜젝션의 수행이 완료됨을 트랜잭션 관리자에게 알려 주는 연산이다.
트랜잭션의 ACID 성질
원자성(Atomicity): 트랜잭션에 포함된 작업은 전부 수행되거나 전부 수행되지 않아야 한다.
일관성(Consistency): 트랜잭션을 수행하기 전이나 후나 데이터베이스는 항상 일관된 상태를 유지해야 한다.
고립성(Isolation): 수행 중인 트랜잭션에 다른 트랜잭션이 끼어들어 변경중인 데이터 값을 훼손하지 않아야 한다.
지속성(Durability): 수행을 성공적으로 완료한 트랜잭션은 변경한 데이터를 영구히 저장해야 한다.
트랜잭션과 DBMS
DBMS는 원자성을 유지하기 위해 회복(복구)관리자 프로그램을 작동시킴
DBMS는 일관성을 유지하기 위해 동시성 제어 알고리즘과 무결성 제약조건을 활용함
DBMS는 고립성을 유지하기 위해 동시성 제어 알고리즘을 작동시킴
DBMS는 지속성을 유지하기 위해 회복 관리자 프로그램을 이용함
롤백(Rollback): 트랜잭션이 행한 모든 연산을 취소하거나 트랜잭션을 재시작함
DBMS는 일관성을 유지하기 위해 무결성 제약조건을 활용함
DBMS는 고립성을 유지하기 위해 동시성 제어 알고리즘을 작동시킴
DBMS는 지속성을 유지하기 위해 회복 관리자 프로그램을 이용함

트랜잭션은 활동(Active), 부분완료(Partially Committed), 완료(Committed), 실패(Failed), 철회(Aborted)
의 5가지 상태를 가진다.
동시성 제어
다중 사용자 환경에서 둘 이상의 트랜잭션이 동시에 수행될 때, 일관성을 해치지 않도록 트랜잭션의 데이터 접근 제어
다중 사용자 환경의 DBMS는 반드시 지원해야 하는 기능이다.
갱신 손실(Lost Update)
하나의 트랜잭션이 갱신한 내용을 다른 트랜잭션이 덮어씀으로써 갱신이 무효화가 되는 것을 의미
두 개의 트랜잭션이 한 개의 데이터를 동시에 갱신(Update) 할 때 발생
데이터베이스에서 절대 발생하면 안되는 현상이다.
모순성(Inconsistency)
다른 트랜잭션들이 해당 항목 값을 갱신하는 동안 한 트랜잭션이 두 개의 항목 값 중 어떤 것은 갱신되기 전의
값을 읽고 다른 것은 갱신된 후의 값을 읽게 되어 데이터의 불일치가 발생하는 상황
연쇄 복귀(Cascading Rollback)
두 트랜잭션이 동일한 데이터 내용을 접근할 때 발생
한 트랜잭션이 데이터를 갱신한 다음 실패하여 Rollback 연산을 수행하는 과정에서 갱신과 Rollback 연산을 실행하고
있는 사이에 해당 데이터를 읽어서 사용할 때 발생할 수 있는 문제
트랜잭션 스케줄(Transaction Schedule)
직렬 스케줄(Serial Schedule): 하나의 트랜잭션이 실행되고 완료된 후 다른 트랜잭션이 실행
비직렬 스케줄(Noneserial Schedule): 직렬 수행 순서와 상관없이 병행 수행하는 스케줄
직렬 가능 스케줄(Serializable Schedule): 서로 영향을 주지 않는 직렬 스케줄을 비직렬적으로 수행
직렬 가능 스케줄
두 개의 트랜잭션이 Read 연산만을 수행할 경우, 상호 간섭이 발생되지 않으며, 연산의 순서도 중요하지 않다.
두 개의 트랜잭션이 같은 데이터 항목에 접근하지 않는다면, 상호 간섭이 발생하지 않으며, 연산의 순서도 중용하지 않다.
Write연산과 Read | Write 연산이 겹칠 경우, 실행 순서는 중요하다.
락(Lock)
로킹(Locking) 기법: 트랜잭션들이 동일한 데이터 항목에 대해 임의적인 병행 접근을 하지 못하도록 제어

트랜잭션 T가 데이터 항목 X에 대해 Read(X) or Write(X)연산을 수행하려면 반드시 lock(X) 연산을 해주어야 한다.
트랜잭션 T가 실행한 lock(X)에 대해서는 해당 트랜잭션이 종료되기 전에 반드시 unlock(X) 연산을 해주어야 한다.
트랜잭션 T는 다른 트랜잭션에 의해 이미 lock이 걸려있는 X에 대해 다시 lock(X)를 수행시키지 못한다.
트랜잭션 T가 X에 lock을 걸지 ㅇ낳았다면, unlock(X)를 수행할 수 없다.
락은 트랜잭션이 읽기를 할 때 사용하는 공유락(LS, Shared Lock)와 읽고 쓰기를 할 때 사용하는
배타락(LX, Exclusive Lock)으로 나누어진다.

트랜잭션 T가 데이터 항목 X에 대해 Shared-Lock을 설정할 경우,
트랜잭션 T는 해당 데이터 항목에 대해서 읽을 수 있지만, 기록할 수 없다.
Read는 서로 영향을 주지 않아서 다른 트랜잭션도 Shared-Lock을 동시에 설정할 수 있다.

트랜잭션 T가 데이터 항목 X에 대하여 Exclusive-Lock을 설정할 경우,
트랜잭션 T는 해당 데이터 항목에 대해서 읽을 수도 없고, 기록할 수도 없다.
공유락 & 배타락 사용 규칙
- 데이터에 락이 걸려있지 않으면 트랜잭션은 데이터에 락을 걸 수 있다.
- 트랜잭션이 데이터 X를 읽기만 하는 경우 LS(X)를 요청, 읽거나 쓸 경우 LX(X)를 요청
- 다른 트랜잭션이 데이터에 LS(X)를 걸어둔 경우, LS(X)의 요청은 허용하고, LX(X)는 허용하지 않는다.
- 다른 트랜잭션이 데이터에 LX(X)를 걸어둔 경우, LS(X)와 LX(X) 모두 허용하지 않는다.
- 트랜잭션이 락을 허용받지 못하면 대기 상태가 된다.
2단계 락킹
로킹 단위: 로킹 기법에서 사용하는 lock 연산의 대상

2단계 로킹 규약: 락을 걸고 해제하는 시점에 제한을 두지 않으면, 두 개의 트랜잭션이 동시에 실행될 때
    데이터의 일관성이 깨질 수 있어서 로킹 단계를 2개로 구분하여 이를 방지하는 방법

확장 단계(Growing Phase): 트랜잭션은 새로운 lock 연산만 할 수 있고, unlock 연산은 할 수 없는 단계
축소 단계(Shrinking Phase): 트랜잭션은 unlock 연산만 실행할 수 있고, lock 연산은 실행할 수 없는 단계

2단계 로킹 규약(2PLP: Two-Phase Locking Protocol)은 트랜잭션들이 lock하는 시간과 unlock하는 시간을
구분하여 수행하도록 하는 방법이다.
확장단계와 축소단계를 두어 이를 해결한다.

교착상태(데드락, Deadlock)에 빠질 수 있으므로 이를 해결해 주어야 한다.
데드락(Deadlock, 교착 상태)
데드락은 두 개 이상의 트랜잭션이 각각 자신의 데이터에 대하여 락을 획득하고 상대방 데이터에 대하여
락을 요청하면 무한 대기 상태에 빠질 수 있는 현상을 말한다.
트랜잭션 고립 수준
- 오손읽기(Dirty Read)
읽기 작업을 하는 트랜잭션 1이 쓰기 작업을 하는 트랜잭션2가 작업한 데이터를 익기 때문에 발생하는 문제
작업중인 트랜잭션 2가 작업을 Rollback한 경우 트랜잭션 1은 무효가 된 데이터를 읽게 되고 잘못된 결과를 도출
- 반복불가능 읽기(Non-repeatable Read)
트랜잭션 1이 데이터를 읽고 트랜잭션 2가 데이터를 쓰고(Update) 트랜잭션 1이 다시 한번 데이터를 읽을 때 발생하는 문제
트랜잭션 1이 읽기 작업을 다시 한번 반복할 경우 이전의 결과와 다른 결과가 나오는 현상
- 유령데이터 읽기(Phantom Read)
트랜잭션 1이 데이터를 읽고, 트랜잭션 2가 데이터를 쓰고(Insert) 트랜잭션 1이 다시 한번 데이터를 읽을 때 생기는 문제
트랜잭션 1이 읽기 작업을 다시 한번 반복할 경우, 이전에 없던 데이터(유령 데이터)가 나타나는 현상
트랜잭션 고립 수준 명령어(Transaction Isolation Level Instruction)
DBMS는 트랜잭션을 동시에 실행시키면서 락보다 좀 더 완하된 방법으로 문제를 해결하기 위해 제공하는 명령어
READ UNCOMMITTED
READ COMMITTED
REPEATABLE READ
SERIALIZABLE 등
READ UNCOMMITTED
고립 수준이 Level 0으로 가장 낮은 명령어, 자신의 데이터에 아무런 공유락을 걸지 않는다.

자신의 데이터에 아무런 공유락도 걸지 않지만, 배타락은 데이터의 갱신손실 문제 때문에 걸어주어야 한다.
다른 트랜잭션에 공유락과 배타락이 걸린 데이터를 대기하지 않고 읽는다.
READ COMMITTED
고립 수준이 Level 1인 명령어로, 오손 페이지의 참조를 피하기 위해 자신의 데이터를 읽는 동안 공유락을 걸지만,
트랜잭션이 끝나기 전에라도 해지 가능하다.

다른 트랜잭션 데이터는 락 호환성 규칙에 따라 진행된다.
SQL Server가 Default로 사용하는 Isolation Level로 SELECT문이 수행되는 동안에
Shared Lock이 걸리게 된다.(데이터를 변경하는 동안 다른 사용자는 해당 데이터에 접근 불가능
REPEATABLE READ
고립 수준이 Level 2인 명령어로, 자신의 데이터에 설정된 공유락과 배타락을 종료될 때까지 유지하여
다른 트랜잭션이 자신의 데이터를 갱신(Update)할 수 없도록 한다.

다른 트랜잭션 데이터는 락 호환성 규칙에 따라 진행된다.
다른 고립화 수준에 비해 데이터의 동시성(Concurrency)이 낮아 특별하지 않은 상황이라면,
사용하지 않는 것이 좋다.

트랜잭션이 완료될 때까지 SELECT문이 사용하는 모든 데이터에 Shared Lock이 걸리므로,
다른 사용자는 그 영역에 해당하는 데이터에 대한 수정이 불가능하다.
SERIALIZABLE
고립 수준이 Level 3으로 가장 높은 명령어로, 실행 중인 트랜잭션은 다른 트랜잭션으로부터 완벽하게 분리된다.

데이터 집합에 범위를 지어 잠금을 설정할 수 있기 때문에 다른 사용자가 데이터를 변경(UPDATE) 또는
삽입(Insert) 하려고 할 때, 트랜잭션을 완벽하게 분리할 수 있다.

가장 제한이 심하고, 동시성도 낮다.
SELECT 문을 사용하는 모든 데이터에 Shared Lock이 걸리므로 다른 사용자는 그 영역에 해당되는 데이터에 대한
수정(UPDATE) 및 입력(INSERT)가 불가능하다.
회복(Recovery)
장애의 유형
- 트랜잭션 장애: 트랜잭션의 실행 시 논리적인 오류로 발생할 수 있는 에러 상황
- 시스템 장애: H/W 시스템 자체에서 발생할 수 있는 에러 상황
- 미디어 장애: 디스크 자체에 손상으로 발생할 수 있는 에러 상황

회복: 데이터베이스 장애가 발생했던 이전의 상태로 복구시켜서 일관된 데이터베이스 상태를 만듬

데이터베이스를 갱신하는 과정에서 장애가 발생한 경우,
회복절차를 수행하여 장애 발생 이전의 데이터베이스로 만드는 것을 회복이라고 한다.
회복을 위한 데이터 복사본을 만드는 방법은 덤프(Dump)와 로그(Log) 2가지가 있다.

덤프(Dump): 가장 기본적인 기법으로 일정 주기로 원본의 데이터베이스의 모든 내용을 다른 저장장치에 복사한다.
로그(Log): 로그는 변경 이전의 데이터베이스를 기준으로 변경 연산이 발생할 때마다 로그 파일을 작성하여 기록하고,
    회복할 때 로그에 적힌 내용을 사용하여 복원한다.
로그 파일(Log File)
트랜잭션이 반영한 모든 데이터의 변경사항을 데이터베이스에 기록하기 전에 미리 기록해두는 별도의 데이터베이스
하드디스크에 저장되어 전원과 관계없이 기록이 존재한다.

로그구조
<트랜잭션 번호, 로그 타입, 데이터 항목 이름, 수정 전 값, 수정 후 값>

로그의 타입: START, INSERT, UPDATE, DELETE, ABORT, COMMIT 등 트랜잭션의 연산 타입
DBMS는 트랜잭션이 종료되었는지 혹은 중단되었는지 여부를 판단하여 종료된 경우에는 종료를 확정하기 위하여
REDO(재시행)하고 중단된 경우에는 없던 일로 되돌리기 위해 UNDO(취소)를 진행한다.

REDO는 장애가 발생한 후 시스템을 재가동 했을 때, 로그 파일에 트랜잭션의 시작(START)는 있고,
종료(COMMIT)이 있는 경우 로그를 보면서 트랜잭션이 변경한 내용을 다시 기록한다.
UNDO는 장애가 발생한 후 시스템을 재가동 했을 때, 로그 파일에 트랜잭션의 시작(START)만 있고,
종료(COMMIT)이 없는 경우 완료하지 못했지만 버퍼의 내용이 데이터베이스에 기록되어 있을 가능성이 있기 때문에
로그를 이용해서 트랜잭션이 변경한 내용을 원상복구시키는 과정이다.


로그 파일의 회복 방법
즉시 갱신(Immediate Update): 갱신 데이터->로그, 버퍼->데이터베이스 작업이 부분완료 전에
    동시에 진행될 수 있으며, 부분 완료가 되면 갱신 데이터는 로그에 기록이 끝난 상태이다.

지연 갱신(Defferred Update): 갱신 데이터->로그가 끝난 후 부분 완료를 하고 버퍼->데이터베이스 작업이
    진행되는 방법
체크포인트(CheckPoint, 검사점)
로그는 기록을 유지하면서, 회복 관리자가 정하는 일정한 시간 간격으로 검사 시점을 생성
회복 시 많은 양의 로그를 검색하고 갱신하는 시간을 줄이기 위함
체크포인트가 있으면 로그를 이용한 회복 기법이 좀 더 간단해진다.

체크포인트를 로그 파일에 아래와 같이 표시
<Checkpoint T_List>        — T_List는 현재 수행 중인 트랜잭션의 리스트

체크포인트 이전에 [Commit] 기록이 있는 경우: 아무 작업이 필요 없다.
체크포인트 이후에[Commit] 기록이 있는 경우: REDO(T)를 진행
체크포인트 이후에 [Commit] 기록이 없는 경우: 즉시 갱신 방법 사용시 UNDO(T) 진행